#include <bits/stdc++.h>
using namespace std;

struct PassWindow {
    string sat_id;
    string target_id;
    long long start; // epoch seconds
    long long end;
};

struct Task {
    string sat_id;
    string target_id;
    long long obs_start;
    long long obs_end;
};

vector<PassWindow> read_passwindows(const string &csv_path) {
    vector<PassWindow> res;
    ifstream f(csv_path);
    if (!f.is_open()) {
        cerr << "Cannot open " << csv_path << "\n";
        return res;
    }
    string line;
    if (!getline(f, line)) return res;
    // parse header to find indices
    vector<string> header;
    {
        stringstream ss(line);
        string tok;
        while (getline(ss, tok, ',')) {
            // trim spaces
            while(!tok.empty() && isspace((unsigned char)tok.front())) tok.erase(tok.begin());
            while(!tok.empty() && isspace((unsigned char)tok.back())) tok.pop_back();
            header.push_back(tok);
        }
    }
    unordered_map<string,int> idx;
    for (int i=0;i<(int)header.size();++i) {
        string h = header[i];
        // normalize to lower
        for (auto &c:h) c = tolower(c);
        idx[h] = i;
    }
    // required columns in your file: Satellite, Target, StartTime, EndTime
    bool hasCols = idx.count("satellite") && idx.count("target") && idx.count("starttime") && idx.count("endtime");
    while (getline(f, line)) {
        if (line.empty()) continue;
        vector<string> toks;
        stringstream ss(line);
        string tok;
        while (getline(ss, tok, ',')) {
            toks.push_back(tok);
        }
        if (!hasCols) {
            // fallback: try old simple 4-column parse
            if (toks.size() < 4) continue;
            PassWindow p;
            p.sat_id = toks[0];
            p.target_id = toks[1];
            try {
                p.start = stoll(toks[2]);
                p.end = stoll(toks[3]);
            } catch (...) { continue; }
            if (p.end <= p.start) continue;
            res.push_back(p);
            continue;
        }
        // safe index checks
        try {
            PassWindow p;
            p.sat_id = toks.at(idx.at("satellite"));
            p.target_id = toks.at(idx.at("target"));
            p.start = stoll(toks.at(idx.at("starttime")));
            p.end = stoll(toks.at(idx.at("endtime")));
            if (p.end <= p.start) continue;
            res.push_back(p);
        } catch (...) {
            continue;
        }
    }
    return res;
}

// Greedy scheduler: for windows that match target and end <= task_end_time
vector<Task> greedy_schedule(const vector<PassWindow> &windows,
                             const string &target,
                             long long task_end_time,
                             long long min_obs_dur,
                             long long max_obs_dur,
                             long long min_gap_between_tasks)
{
    // 过滤相关窗口
    vector<PassWindow> cand;
    for (auto &w : windows) {
        if (w.target_id != target) continue;
        if (w.start > task_end_time) continue;
        // 通过task_end_time截断end
        PassWindow t = w;
        if (t.end > task_end_time) t.end = task_end_time;
        if (t.end - t.start < min_obs_dur) continue;
        cand.push_back(t);
    }
    // 按开始时间排序（最早的优先）
    sort(cand.begin(), cand.end(), [](const PassWindow &a, const PassWindow &b) {
        if (a.start != b.start) return a.start < b.start;
        if (a.end != b.end) return a.end < b.end;
        return a.sat_id < b.sat_id;
    });

    // 跟踪每颗卫星的最后繁忙时间
    unordered_map<string, long long> sat_busy_until; // epoch seconds

    vector<Task> tasks;
    for (const auto &w : cand) {
        long long available_from = w.start;
        // 如果卫星忙，最早可能的开始是busy_until + gap
        auto it = sat_busy_until.find(w.sat_id);
        if (it != sat_busy_until.end()) {
            long long earliest = it->second + min_gap_between_tasks;
            if (earliest > available_from) available_from = earliest;
        }
        if (available_from >= w.end) continue; // cannot fit
        // 选择观察时间：贪婪地尽可能长，直到max_obs_dur
        long long possible_dur = w.end - available_from;
        long long obs_dur = min(possible_dur, max_obs_dur);
        if (obs_dur < min_obs_dur) continue;
        Task t;
        t.sat_id = w.sat_id;
        t.target_id = w.target_id;
        t.obs_start = available_from;
        t.obs_end = available_from + obs_dur;
        tasks.push_back(t);
        // 标记卫星忙
        sat_busy_until[w.sat_id] = t.obs_end;
    }
    return tasks;
}

void write_tasks_csv(const string &out_path, const vector<Task> &tasks) {
    ofstream f(out_path);
    if (!f.is_open()) {
        cerr << "Cannot open output " << out_path << "\n";
        return;
    }
    f << "sat_id,target_id,obs_start,obs_end,duration\n";
    for (auto &t : tasks) {
        f << t.sat_id << "," << t.target_id << "," << t.obs_start << "," << t.obs_end << "," << (t.obs_end - t.obs_start) << "\n";
    }
    f.close();
}

// 内置测试入口（在无参数运行时调用）
void run_builtin_test() {
    // 请确保这个路径存在于你的工作区
    string csv = "e:\\\\by_works\\\\state_lite_orbit\\\\yk_related\\\\passwindow.csv";
    string target = "6";           // 测试使用的 Target 列值（可改为 Target_name，如 "ship_6"）
    long long task_end = 7200;     // 测试任务截止时间
    long long min_obs = 10;        // 最短观测时长（秒）
    long long max_obs = 300;       // 最长观测时长（秒）
    long long min_gap = 5;         // 同一卫星任务最小间隔（秒）

    cout << "Running built-in test with:\n"
         << "  csv=" << csv << "\n"
         << "  target=" << target << "  task_end=" << task_end << "\n";

    auto windows = read_passwindows(csv);
    if (windows.empty()) {
        cerr << "No pass windows parsed from CSV. Check path or CSV format.\n";
        return;
    }
    auto tasks = greedy_schedule(windows, target, task_end, min_obs, max_obs, min_gap);
    write_tasks_csv("tasks_out_test.csv", tasks);
    cout << "Built-in test scheduled " << tasks.size() << " tasks. Output to tasks_out_test.csv\n";
}

int main(int argc, char **argv) {
    if (argc == 1) {
        // 无参数：运行内置测试
        run_builtin_test();
        return 0;
    }
    if (argc < 6) {
        cerr << "Usage: " << argv[0] << " passwindow.csv target_id task_end_epoch min_obs_dur max_obs_dur [min_gap]\n";
        return 1;
    }
    string csv = argv[1];
    string target = argv[2];
    long long task_end = stoll(argv[3]);
    long long min_obs = stoll(argv[4]);
    long long max_obs = stoll(argv[5]);
    long long min_gap = 0;
    if (argc >= 7) min_gap = stoll(argv[6]);

    auto windows = read_passwindows(csv);
    auto tasks = greedy_schedule(windows, target, task_end, min_obs, max_obs, min_gap);
    write_tasks_csv("tasks_out.csv", tasks);
    cout << "Scheduled " << tasks.size() << " tasks. Output to tasks_out.csv\n";
    return 0;
}

// 编译与运行指令示例（Windows PowerShell）
// g++ -std=c++17 point_scheduler.cpp -O2 -o point_scheduler.exe
// .\point_scheduler.exe